Išsamus Python SQLAlchemy sesijų valdymo vadovas, kuriame daugiausia dėmesio skiriama patikimoms transakcijų tvarkymo technikoms, siekiant užtikrinti duomenų vientisumą ir nuoseklumą jūsų programose.
Python SQLAlchemy sesijų valdymas: transakcijų tvarkymo įvaldymas duomenų vientisumui užtikrinti
SQLAlchemy yra galinga ir lanksti Python biblioteka, kuri suteikia išsamų įrankių rinkinį darbui su duomenų bazėmis. SQLAlchemy pagrindas yra sesijos (session) koncepcija, kuri veikia kaip visų operacijų, kurias atliekate su duomenų baze, paruošiamoji zona. Tinkamas sesijų ir transakcijų valdymas yra gyvybiškai svarbus norint išlaikyti duomenų vientisumą ir užtikrinti nuoseklų duomenų bazės elgesį, ypač sudėtingose programose, apdorojančiose konkurentiškas užklausas.
SQLAlchemy sesijų supratimas
SQLAlchemy sesija (Session) reiškia darbo vienetą, pokalbį su duomenų baze. Ji seka objektų pakeitimus, leisdama juos išsaugoti duomenų bazėje kaip vieną atominę operaciją. Įsivaizduokite tai kaip darbo erdvę, kurioje atliekate duomenų pakeitimus prieš juos oficialiai išsaugodami. Be gerai valdomos sesijos rizikuojate duomenų nenuoseklumu ir galimu sugadinimu.
Sesijos sukūrimas
Prieš pradedant sąveikauti su duomenų baze, turite sukurti sesiją. Tam pirmiausia reikia užmegzti ryšį su duomenų baze naudojant SQLAlchemy variklį (engine).
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
# Database connection string
db_url = 'sqlite:///:memory:' # Replace with your database URL (e.g., PostgreSQL, MySQL)
# Create an engine
engine = create_engine(db_url, echo=False) # echo=True to see the generated SQL
# Define a base for declarative models
Base = declarative_base()
# Define a simple model
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
def __repr__(self):
return f""
# Create the table in the database
Base.metadata.create_all(engine)
# Create a session class
Session = sessionmaker(bind=engine)
# Instantiate a session
session = Session()
Šiame pavyzdyje:
- Importuojame reikiamus SQLAlchemy modulius.
- Apibrėžiame duomenų bazės prisijungimo eilutę (`db_url`). Šiame pavyzdyje paprastumo dėlei naudojama atmintyje esanti SQLite duomenų bazė, tačiau ją reikėtų pakeisti prisijungimo eilute, tinkama jūsų duomenų bazės sistemai (pvz., PostgreSQL, MySQL). Konkretus formatas priklauso nuo naudojamo duomenų bazės variklio ir tvarkyklės. Teisingą prisijungimo eilutės formatą rasite SQLAlchemy ir jūsų duomenų bazės tiekėjo dokumentacijoje.
- Sukuriame `engine` (variklį) naudodami `create_engine()`. Variklis yra atsakingas už prisijungimų telkinio (connection pool) valdymą ir komunikaciją su duomenų baze. Parametras `echo=True` gali būti naudingas derinant programą, nes jis išves sugeneruotas SQL užklausas į konsolę.
- Apibrėžiame bazinę klasę (`Base`) naudodami `declarative_base()`. Ji naudojama kaip bazinė klasė visiems mūsų SQLAlchemy modeliams.
- Apibrėžiame `User` modelį, susiedami jį su duomenų bazės lentele, pavadinta `users`.
- Sukuriame lentelę duomenų bazėje naudodami `Base.metadata.create_all(engine)`.
- Sukuriame sesijos klasę naudodami `sessionmaker(bind=engine)`. Tai sukonfigūruoja sesijos klasę naudoti nurodytą variklį.
- Galiausiai, sukuriame sesijos egzempliorių naudodami `Session()`.
Transakcijų supratimas
Transakcija yra duomenų bazės operacijų seka, traktuojama kaip vienas loginis darbo vienetas. Transakcijos atitinka ACID savybes:
- Atomiškumas: Visos transakcijos operacijos arba įvykdomos sėkmingai, arba visiškai atšaukiamos. Jei kuri nors transakcijos dalis nepavyksta, visa transakcija yra atšaukiama.
- Nuoseklumas: Transakcija turi palaikyti duomenų bazę galiojančioje būsenoje. Ji negali pažeisti jokių duomenų bazės apribojimų ar taisyklių.
- Izoliacija: Konkurentiškos transakcijos yra izoliuotos viena nuo kitos. Vienos transakcijos atlikti pakeitimai nėra matomi kitoms transakcijoms, kol pirmoji transakcija nebus patvirtinta.
- Patvarumas: Kai transakcija yra patvirtinta, jos pakeitimai yra nuolatiniai ir išliks net ir sistemos gedimų atveju.
SQLAlchemy suteikia mechanizmus transakcijoms valdyti, užtikrinančius šių ACID savybių laikymąsi.
Pagrindinis transakcijų tvarkymas
Dažniausios transakcijų operacijos yra patvirtinimas (commit) ir atšaukimas (rollback).
Transakcijų patvirtinimas (Commit)
Kai visos operacijos transakcijos viduje yra sėkmingai užbaigtos, jūs patvirtinate (commit) transakciją. Tai išsaugo pakeitimus duomenų bazėje.
try:
# Add a new user
new_user = User(name='Alice Smith', email='alice.smith@example.com')
session.add(new_user)
# Commit the transaction
session.commit()
print("Transaction committed successfully!")
except Exception as e:
# Handle exceptions
print(f"An error occurred: {e}")
session.rollback()
print("Transaction rolled back.")
finally:
session.close()
Šiame pavyzdyje:
- Pridedame naują `User` objektą į sesiją.
- Iškviečiame `session.commit()`, kad išsaugotume pakeitimus duomenų bazėje.
- Kodą apgaubiame `try...except...finally` bloku, kad apdorotume galimas išimtis.
- Įvykus išimčiai, iškviečiame `session.rollback()`, kad atšauktume visus transakcijos metu atliktus pakeitimus.
- Visada iškviečiame `session.close()` `finally` bloke, kad atlaisvintume sesiją ir grąžintume prisijungimą į prisijungimų telkinį. Tai yra kritiškai svarbu siekiant išvengti resursų nutekėjimo. Neuždarius sesijų, gali išsekti prisijungimai ir sutrikti programos stabilumas.
Transakcijų atšaukimas (Rollback)
Jei transakcijos metu įvyksta klaida arba jei nusprendžiate, kad pakeitimai neturėtų būti išsaugoti, jūs atšaukiate (rollback) transakciją. Tai grąžina duomenų bazę į būseną, buvusią prieš pradedant transakciją.
try:
# Add a user with an invalid email (example to force a rollback)
invalid_user = User(name='Bob Johnson', email='invalid-email')
session.add(invalid_user)
# The commit will fail if the email is not validated on the database level
session.commit()
print("Transaction committed.")
except Exception as e:
print(f"An error occurred: {e}")
session.rollback()
print("Transaction rolled back successfully.")
finally:
session.close()
Šiame pavyzdyje, jei pridedant `invalid_user` įvyksta išimtis (pvz., dėl duomenų bazės apribojimo pažeidimo), `session.rollback()` iškvietimas atšauks bandymą įterpti duomenis, palikdamas duomenų bazę nepakeistą.
Pažangus transakcijų valdymas
Konstrukcijos `with` naudojimas transakcijų apimčiai
Patogesnis ir patikimesnis būdas valdyti transakcijas yra naudoti `with` konstrukciją. Tai užtikrina, kad sesija bus tinkamai uždaryta, net jei įvyks išimčių.
from contextlib import contextmanager
@contextmanager
def session_scope():
"""Provide a transactional scope around a series of operations."""
session = Session()
try:
yield session
session.commit()
except Exception:
session.rollback()
raise
finally:
session.close()
# Usage:
with session_scope() as session:
new_user = User(name='Charlie Brown', email='charlie.brown@example.com')
session.add(new_user)
# Operations within the 'with' block
# If no exceptions occur, the transaction is committed automatically.
# If an exception occurs, the transaction is rolled back automatically.
print("User added.")
print("Transaction completed (committed or rolled back).")
`session_scope` funkcija yra konteksto tvarkyklė (context manager). Įeinant į `with` bloką, sukuriama nauja sesija. Išeinant iš `with` bloko, sesija arba patvirtinama (jei neįvyko išimčių), arba atšaukiama (jei įvyko išimtis). Sesija visada uždaroma `finally` bloke.
Įdėtosios transakcijos (išsaugojimo taškai - Savepoints)
SQLAlchemy palaiko įdėtąsias transakcijas naudojant išsaugojimo taškus (savepoints). Išsaugojimo taškas leidžia atšaukti operacijas iki konkretaus taško didesnės transakcijos viduje, nepaveikiant visos transakcijos.
try:
with session_scope() as session:
user1 = User(name='David Lee', email='david.lee@example.com')
session.add(user1)
session.flush() # Send changes to the database but don't commit yet
# Create a savepoint
savepoint = session.begin_nested()
try:
user2 = User(name='Eve Wilson', email='eve.wilson@example.com')
session.add(user2)
session.flush()
# Simulate an error
raise ValueError("Simulated error during nested transaction")
except Exception as e:
print(f"Nested transaction error: {e}")
savepoint.rollback()
print("Nested transaction rolled back to savepoint.")
# Continue with the outer transaction, user1 will still be added
user3 = User(name='Frank Miller', email='frank.miller@example.com')
session.add(user3)
except Exception as e:
print(f"Outer transaction error: {e}")
#Commit will commit user1 and user3, but not user2 due to the nested rollback
try:
with session_scope() as session:
#Verify only user1 and user3 exist
users = session.query(User).all()
for user in users:
print(user)
except Exception as e:
print(f"Unexpected Exception: {e}") #Should not happen
Šiame pavyzdyje:
- Pradedame išorinę transakciją naudodami `session_scope()`.
- Pridedame `user1` į sesiją ir nusiunčiame pakeitimus į duomenų bazę. `flush()` išsiunčia pakeitimus į duomenų bazės serverį, bet jų nepatvirtina (does not commit). Tai leidžia pamatyti, ar pakeitimai yra galiojantys (pvz., nėra apribojimų pažeidimų), prieš patvirtinant visą transakciją.
- Sukuriame išsaugojimo tašką naudodami `session.begin_nested()`.
- Įdėtosios transakcijos viduje pridedame `user2` ir simuliuojame klaidą.
- Atšaukiame įdėtąją transakciją iki išsaugojimo taško naudodami `savepoint.rollback()`. Tai atšaukia tik įdėtosios transakcijos metu atliktus pakeitimus (t. y., `user2` pridėjimą).
- Tęsiame išorinę transakciją ir pridedame `user3`.
- Išorinė transakcija yra patvirtinama, išsaugant `user1` ir `user3` duomenų bazėje, o `user2` yra atmetamas dėl išsaugojimo taško atšaukimo.
Izoliacijos lygių valdymas
Izoliacijos lygiai apibrėžia, kokiu laipsniu konkurentiškos transakcijos yra izoliuotos viena nuo kitos. Aukštesni izoliacijos lygiai užtikrina didesnį duomenų nuoseklumą, bet gali sumažinti konkurentiškumą ir našumą. SQLAlchemy leidžia valdyti jūsų transakcijų izoliacijos lygį.
Dažniausi izoliacijos lygiai:
- Read Uncommitted (neskaityti patvirtintų): Žemiausias izoliacijos lygis. Transakcijos gali matyti kitų transakcijų atliktus, bet dar nepatvirtintus pakeitimus. Tai gali sukelti nešvarius nuskaitymus (dirty reads).
- Read Committed (skaityti patvirtintus): Transakcijos gali matyti tik kitų transakcijų atliktus ir patvirtintus pakeitimus. Tai apsaugo nuo nešvarių nuskaitymų, bet gali sukelti nepasikartojančius nuskaitymus (non-repeatable reads) ir fantominius nuskaitymus (phantom reads).
- Repeatable Read (pasikartojantis nuskaitymas): Transakcijos mato tuos pačius duomenis visos transakcijos metu, net jei kitos transakcijos juos keičia. Tai apsaugo nuo nešvarių ir nepasikartojančių nuskaitymų, bet gali sukelti fantominius nuskaitymus.
- Serializable (serializuojamas): Aukščiausias izoliacijos lygis. Transakcijos yra visiškai izoliuotos viena nuo kitos. Tai apsaugo nuo nešvarių, nepasikartojančių ir fantominių nuskaitymų, bet gali žymiai sumažinti konkurentiškumą.
Numatytasis izoliacijos lygis priklauso nuo duomenų bazės sistemos. Galite nustatyti izoliacijos lygį kuriant variklį arba pradedant transakciją.
Pavyzdys (PostgreSQL):
from sqlalchemy.dialects.postgresql import dialect
# Set isolation level when creating the engine
engine = create_engine('postgresql://user:password@host:port/database',
connect_args={'options': '-c statement_timeout=1000'} #Example of timeout
)
# Set the isolation level when beginning a transaction (database specific)
# For postgresql, it's recommended to set it on the connection, not engine.
from sqlalchemy import event
from sqlalchemy.pool import Pool
@event.listens_for(Pool, "connect")
def set_isolation_level(dbapi_connection, connection_record):
existing_autocommit = dbapi_connection.autocommit
dbapi_connection.autocommit = True
cursor = dbapi_connection.cursor()
cursor.execute("SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE")
dbapi_connection.autocommit = existing_autocommit
cursor.close()
# Then transactions created via SQLAlchemy will use the configured isolation level.
Svarbu: Izoliacijos lygių nustatymo metodas priklauso nuo konkrečios duomenų bazės. Teisingą sintaksę rasite savo duomenų bazės dokumentacijoje. Neteisingai nustatyti izoliacijos lygiai gali sukelti netikėtą elgesį ar klaidas.
Konkurentiškumo tvarkymas
Kai keli vartotojai ar procesai vienu metu pasiekia tuos pačius duomenis, labai svarbu tinkamai tvarkyti konkurentiškumą, kad būtų išvengta duomenų sugadinimo ir užtikrintas jų nuoseklumas. SQLAlchemy siūlo kelis mechanizmus konkurentiškumui tvarkyti, įskaitant optimistinį ir pesimistinį blokavimą.
Optimistinis blokavimas
Optimistinis blokavimas daro prielaidą, kad konfliktai yra reti. Prieš patvirtinant transakciją, patikrinama, ar kitos transakcijos neatliko pakeitimų. Jei aptinkamas konfliktas, transakcija yra atšaukiama.
Norint įgyvendinti optimistinį blokavimą, paprastai į lentelę pridedamas versijos stulpelis. Šis stulpelis automatiškai padidinamas kiekvieną kartą, kai atnaujinama eilutė.
from sqlalchemy import Column, Integer, String, Integer
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class Article(Base):
__tablename__ = 'articles'
id = Column(Integer, primary_key=True)
title = Column(String)
content = Column(String)
version = Column(Integer, nullable=False, default=1)
def __repr__(self):
return f""
#Inside of the try catch block
def update_article(session, article_id, new_content):
article = session.query(Article).filter_by(id=article_id).first()
if article is None:
raise ValueError("Article not found")
original_version = article.version
# Update the content and increment the version
article.content = new_content
article.version += 1
# Attempt to update, checking the version column in the WHERE clause
rows_affected = session.query(Article).filter(
Article.id == article_id,
Article.version == original_version
).update({
Article.content: new_content,
Article.version: article.version
}, synchronize_session=False)
if rows_affected == 0:
session.rollback()
raise ValueError("Conflict: Article has been updated by another transaction.")
session.commit()
Šiame pavyzdyje:
- Į `Article` modelį pridedame `version` stulpelį.
- Prieš atnaujindami straipsnį, išsaugome dabartinį versijos numerį.
- `UPDATE` sakinyje įtraukiame `WHERE` sąlygą, kuri patikrina, ar versijos stulpelis vis dar lygus išsaugotam versijos numeriui. `synchronize_session=False` neleidžia SQLAlchemy iš naujo įkelti atnaujinto objekto; mes aiškiai tvarkome versijavimą.
- Jei versijos stulpelį pakeitė kita transakcija, `UPDATE` sakinys nepaveiks jokių eilučių (rows_affected bus 0), ir mes iškelsime išimtį.
- Atšaukiame transakciją ir pranešame vartotojui, kad įvyko konfliktas.
Pesimistinis blokavimas
Pesimistinis blokavimas daro prielaidą, kad konfliktai yra tikėtini. Prieš modifikuojant eilutę ar lentelę, jai pritaikomas užraktas. Tai neleidžia kitoms transakcijoms keisti duomenų, kol užraktas nebus atleistas.
SQLAlchemy suteikia kelias funkcijas užraktams gauti, pavyzdžiui, `with_for_update()`.
# Example using PostgreSQL
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
# Database setup (replace with your actual database URL)
db_url = 'postgresql://user:password@host:port/database'
engine = create_engine(db_url, echo=False) #Set echo to true if you would like to see the SQL generated
Base = declarative_base()
class Item(Base):
__tablename__ = 'items'
id = Column(Integer, primary_key=True)
name = Column(String)
value = Column(Integer)
def __repr__(self):
return f"- "
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
#Function to update the item (within a try/except)
def update_item_value(session, item_id, new_value):
# Acquire a pessimistic lock on the item
item = session.query(Item).filter(Item.id == item_id).with_for_update().first()
if item is None:
raise ValueError("Item not found")
# Update the item's value
item.value = new_value
session.commit()
return True
Šiame pavyzdyje:
- Naudojame `with_for_update()`, kad gautume užraktą `Item` eilutei prieš ją atnaujinant. Tai neleidžia kitoms transakcijoms keisti eilutės, kol dabartinė transakcija nebus patvirtinta ar atšaukta. Funkcija `with_for_update()` priklauso nuo konkrečios duomenų bazės; išsamesnės informacijos ieškokite savo duomenų bazės dokumentacijoje. Kai kurios duomenų bazės gali turėti skirtingus blokavimo mechanizmus ar sintaksę.
Svarbu: Pesimistinis blokavimas gali sumažinti konkurentiškumą ir našumą, todėl naudokite jį tik tada, kai būtina.
Geriausios išimčių tvarkymo praktikos
Tinkamas išimčių tvarkymas yra labai svarbus siekiant užtikrinti duomenų vientisumą ir išvengti programos sutrikimų. Visada apgaubkite savo duomenų bazės operacijas `try...except` blokais ir tinkamai tvarkykite išimtis.
Štai keletas geriausių išimčių tvarkymo praktikų:
- Gaudykite konkrečias išimtis: Venkite gaudyti bendras išimtis, tokias kaip `Exception`. Gaudykite konkrečias išimtis, pvz., `sqlalchemy.exc.IntegrityError` arba `sqlalchemy.exc.OperationalError`, kad skirtingų tipų klaidas tvarkytumėte skirtingai.
- Atšaukite transakcijas: Visada atšaukite transakciją, jei įvyksta išimtis.
- Registruokite išimtis: Registruokite išimtis, kad būtų lengviau diagnozuoti ir ištaisyti problemas. Į savo žurnalus įtraukite kuo daugiau konteksto (pvz., vartotojo ID, įvesties duomenis, laiko žymę).
- Perkelkite išimtis, kai tinkama: Jei negalite apdoroti išimties, perkelkite ją aukštesnio lygio tvarkyklei.
- Išvalykite resursus: Visada uždarykite sesiją ir atlaisvinkite visus kitus resursus `finally` bloke.
import logging
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy.exc import IntegrityError, OperationalError
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Database setup (replace with your actual database URL)
db_url = 'postgresql://user:password@host:port/database'
engine = create_engine(db_url, echo=False)
Base = declarative_base()
class Product(Base):
__tablename__ = 'products'
id = Column(Integer, primary_key=True)
name = Column(String)
price = Column(Integer)
def __repr__(self):
return f""
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
# Function to add a product
def add_product(session, name, price):
try:
new_product = Product(name=name, price=price)
session.add(new_product)
session.commit()
logging.info(f"Product '{name}' added successfully.")
return True
except IntegrityError as e:
session.rollback()
logging.error(f"IntegrityError: {e}")
#Handle database constraint violations (e.g., duplicate name)
return False
except OperationalError as e:
session.rollback()
logging.error(f"OperationalError: {e}")
#Handle connection errors or other operational issues
return False
except Exception as e:
session.rollback()
logging.exception(f"An unexpected error occurred: {e}")
# Handle any other unexpected errors
return False
finally:
session.close()
Šiame pavyzdyje:
- Konfigūruojame registravimą (logging), kad būtų įrašomi proceso įvykiai.
- Gaudome konkrečias išimtis, tokias kaip `IntegrityError` (dėl apribojimų pažeidimų) ir `OperationalError` (dėl prisijungimo klaidų).
- Atšaukiame transakciją `except` blokuose.
- Registruojame išimtis naudodami `logging` modulį. `logging.exception()` metodas automatiškai įtraukia klaidų seką (stack trace) į žurnalo pranešimą.
- Perkeliame išimtį, jei negalime jos apdoroti.
- Uždarome sesiją `finally` bloke.
Duomenų bazės prisijungimų telkinys (Pooling)
SQLAlchemy naudoja prisijungimų telkinį (connection pooling) efektyviam duomenų bazės prisijungimų valdymui. Prisijungimų telkinys palaiko atidarytų prisijungimų rinkinį prie duomenų bazės, leidžiant programoms pakartotinai naudoti esamus prisijungimus, o ne kurti naujus kiekvienai užklausai. Tai gali žymiai pagerinti našumą, ypač programose, kurios apdoroja daug konkurentiškų užklausų.
SQLAlchemy `create_engine()` funkcija automatiškai sukuria prisijungimų telkinį. Galite konfigūruoti prisijungimų telkinį perduodami argumentus į `create_engine()`.
Dažniausi prisijungimų telkinio parametrai:
- pool_size: Maksimalus prisijungimų skaičius telkinyje.
- max_overflow: Prisijungimų skaičius, kuris gali būti sukurtas viršijus pool_size.
- pool_recycle: Sekundžių skaičius, po kurio prisijungimas yra pernaudojamas.
- pool_timeout: Sekundžių skaičius, kiek laukti, kol prisijungimas taps pasiekiamas.
engine = create_engine('postgresql://user:password@host:port/database',
pool_size=5, #Maximum pool size
max_overflow=10, #Maximum overflow
pool_recycle=3600, #Recycle connections after 1 hour
pool_timeout=30
)
Svarbu: Pasirinkite tinkamus prisijungimų telkinio nustatymus, atsižvelgdami į savo programos poreikius ir duomenų bazės serverio galimybes. Blogai sukonfigūruotas prisijungimų telkinys gali sukelti našumo problemų arba prisijungimų išsekimą.
Asinchroninės transakcijos (Async SQLAlchemy)
Šiuolaikinėms programoms, reikalaujančioms didelio konkurentiškumo, ypač toms, kurios sukurtos su asinchroninėmis sistemomis, tokiomis kaip FastAPI ar AsyncIO, SQLAlchemy siūlo asinchroninę versiją, vadinamą Async SQLAlchemy.
Async SQLAlchemy suteikia asinchronines pagrindinių SQLAlchemy komponentų versijas, leidžiančias atlikti duomenų bazės operacijas neblokuojant įvykių ciklo (event loop). Tai gali žymiai pagerinti jūsų programų našumą ir mastelį.
Štai pagrindinis Async SQLAlchemy naudojimo pavyzdys:
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import declarative_base
from sqlalchemy import Column, Integer, String
import asyncio
# Database setup (replace with your actual database URL)
db_url = 'postgresql+asyncpg://user:password@host:port/database'
engine = create_async_engine(db_url, echo=False)
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
email = Column(String)
def __repr__(self):
return f""
async def create_db_and_tables():
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
async def add_user(name, email):
async with AsyncSession(engine) as session:
new_user = User(name=name, email=email)
session.add(new_user)
await session.commit()
async def main():
await create_db_and_tables()
await add_user("Async User", "async.user@example.com")
if __name__ == "__main__":
asyncio.run(main())
Pagrindiniai skirtumai nuo sinchroninio SQLAlchemy:
- Naudojama `create_async_engine` vietoj `create_engine`.
- Naudojama `AsyncSession` vietoj `Session`.
- Visos duomenų bazės operacijos yra asinchroninės ir turi būti laukiamos naudojant `await`.
- Turi būti naudojamos asinchroninės duomenų bazės tvarkyklės (pvz., `asyncpg` PostgreSQL).
Svarbu: Async SQLAlchemy reikalauja duomenų bazės tvarkyklės, palaikančios asinchronines operacijas. Įsitikinkite, kad turite įdiegtą ir sukonfigūruotą teisingą tvarkyklę.
Išvados
Įvaldyti SQLAlchemy sesijų ir transakcijų valdymą yra būtina norint kurti patikimas Python programas, kurios sąveikauja su duomenų bazėmis. Suprasdami sesijų, transakcijų, izoliacijos lygių ir konkurentiškumo koncepcijas bei laikydamiesi geriausių išimčių tvarkymo ir prisijungimų telkinių naudojimo praktikų, galite užtikrinti duomenų vientisumą ir optimizuoti savo programų našumą.
Nesvarbu, ar kuriate mažą internetinę programą, ar didelio masto įmonės sistemą, SQLAlchemy suteikia įrankius, reikalingus efektyviam duomenų bazės sąveikų valdymui. Nepamirškite visada teikti pirmenybę duomenų vientisumui ir grakščiai tvarkyti galimas klaidas, kad užtikrintumėte savo programų patikimumą.
Apsvarstykite galimybę išnagrinėti pažangesnes temas, tokias kaip:
- Dviejų fazių patvirtinimas (2PC): Transakcijoms, apimančioms kelias duomenų bazes.
- Skaldymas (Sharding): Duomenų paskirstymui keliuose duomenų bazių serveriuose.
- Duomenų bazių migracijos: Naudojant įrankius, tokius kaip Alembic, duomenų bazių schemos pakeitimams valdyti.